package com.zbj.homemade.spring;

import com.zbj.homemade.spring.beans.BeanAnnotationBeanDefinition;
import com.zbj.homemade.spring.beans.BeanDefinition;
import com.zbj.homemade.spring.beans.BeanDefinitionRegistry;
import com.zbj.homemade.spring.exception.BeanRegistryException;
import com.zbj.homemade.spring.exception.BeansException;
import com.zbj.homemade.spring.lifecycle.Aware;
import com.zbj.homemade.spring.lifecycle.BeanFactoryAware;
import com.zbj.homemade.spring.lifecycle.BeanNameAware;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * |                    .  ’   *   ‘  .
 * |               _6                    "     o0000o
 * |  o00o _    .%                         %. o0000000o
 * | o000000o.:                              :(0000000o
 * | o00000os                                  .000000o
 * |  o0000/     <b>不了不了,改需求真的伤身体</>   .000o
 * |    o0o                                       .0o
 * |     y        <b>我认为源代码,就是SkrSkr</>     .
 * |    y                                           ,
 * |   y          <b>小熊猫保佑,代码永不修改</>        ,
 * |   p                            .                 .
 * |   p                           @@.                .
 * |    y                        ;@@@;               .
 * |    \                       ;@@@@;.@.          ,;S
 * |     、                     .@@@@@@;       ,@@@@@
 * |     @\.            .****...*@@@@;     .@@@@@@@@@@@.
 * |    @@@@\.     . @@@@@@@@@@@@@@@;    .@@@@@@@@@@@@@@@.
 * |   @@@@@@@@@.@@@@@@@@@@@@@@@@;   .@@@@@@@@@@@@@@@@@@@@@.
 * |  @@@@@@..@@@@..@@@@@@..@@@@@ .@@...@@@@@..@@..@@@@@..@@.
 * | @@@@@@@@..@..@@@@@@@@@@@@@;.@@@..@..@@@..@@....@@@..@@@@.
 * |@y@@@@@@@@..@@@@@@@@..@@@@i@@@@..@@@..@..@@..@@..@..@@@@n@.
 * |@n@@@@@@@..@@@@@@@@..@@@@@@@@@..@@@@@...@@..@@@@...@@@@@n@@.
 * |@@@@@@@@..@@@@@@@@..@@@@@@@@@..@@@@@@@.@@..@@@@@..@@@@@@@@@@.
 * |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.
 *
 * @program: principle
 * @description:
 * @author: Yinn
 * @create: 2019-03-01 15:35
 **/
public class SimpleBeanFactory extends AbstractBeanFatory implements BeanDefinitionRegistry {

    private final ConcurrentMap<String, BeanDefinition> beanDefinitions = new ConcurrentHashMap<>(256);

    private volatile List<String> beanDefinitionNames = new ArrayList<>();

    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {

        assert StringUtils.isBlank(beanName) || beanDefinition == null;

        if (beanDefinitions.containsKey(beanName))
            throw new BeanRegistryException("已经存在beanname!");

        this.beanDefinitions.put(beanName, beanDefinition);
        beanDefinitionNames.add(beanName);
    }

    @Override
    public void removeBeanDefinition(String beanName) {
        assert StringUtils.isBlank(beanName);

        beanDefinitions.remove(beanName);
        beanDefinitionNames.remove(beanName);
    }

    @Override
    public BeanDefinition getBeanDefinition(String beanName) {
        assert StringUtils.isBlank(beanName);

        return beanDefinitions.get(beanName);
    }

    @Override
    public boolean containsBeanDefinition(String beanName) {
        assert StringUtils.isBlank(beanName);

        return beanDefinitions.containsKey(beanName);
    }

    @Override
    public String[] getBeanDefinitionNames() {
        return beanDefinitionNames.toArray(new String[0]);
    }

    @Override
    public int getBeanDefinitionCount() {
        return beanDefinitions.size();
    }

    /**
     * 预制所有单例非懒加载对象
     */
    @Override
    protected Object createBean(String beanName, BeanDefinition bd) throws BeansException {
        Class<?> c = bd.getBeanClass();
        try {
            Object create;
            //bean 注解
            // @Bean
            // public Moon moon(Earth e){
            //      return new Moon();
            // }
            if (bd instanceof BeanAnnotationBeanDefinition) {
                BeanAnnotationBeanDefinition babd = ((BeanAnnotationBeanDefinition) bd);
                //实例化构造由@Bean 注解的方法控制
                Method createMethod = babd.getInstantiatedMethod();
                createMethod.setAccessible(true);
                if (createMethod.getParameterTypes() != null && createMethod.getParameterTypes().length > 0) {
                    Object[] args = new Object[createMethod.getParameterTypes().length];
                    for (int i = 0; i < createMethod.getParameterTypes().length; i++) {
                        args[i] = getBean(createMethod.getParameterTypes()[i]);
                    }
                    create = createMethod.invoke(getBean(babd.getConfigClass()), args);
                } else {
                    create = createMethod.invoke(getBean(babd.getConfigClass()), null);
                }

            } else {
                create = c.newInstance();
            }

            if (create == null)
                throw new BeansException("Bean对象创建异常!");

            //适配感知接口
            create = setAdapterInterface(create, beanName);

            //属性注入
            create = setProperties(create, bd);

            //前后-后置处理器 以及初始化方法
            create = initialization(create, beanName);

            //将所有非懒加载且单例的对象 注入缓存/ 加快之后调用速度
            if (!bd.getLazyInit() && BeanDefinition.SCOPE_SINGLETON.equals(bd.getScope())) {
                registerSingleton(beanName, create);
            }


            return create;
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public void preInstantiateSingletons() {

        for (String beanName : this.beanDefinitionNames){
            getBean(beanName);
        }
//        for (Map.Entry<String, BeanDefinition> bdEntry : beanDefinitions.entrySet()) {
//            //会创建所有的bean效率会低。。。。不过无所谓
//            this.getBean(bdEntry.getKey());
//        }
    }

    public List<String> getBeanNamesByType(Class<?> cls) {

        List<String> beanNames = new ArrayList<>();
        for (String name : beanDefinitionNames) {
            BeanDefinition bd = getBeanDefinition(name);
            if (bd != null && bd.getBeanClass() != null && isMatch(cls, bd.getBeanClass())) {
                beanNames.add(name);
            }
        }

        return beanNames;
    }

    /**
     * 类型匹配 child == child 或者 child 是 father的子类 或 实现接口 true
     */
    protected boolean isMatch(Class<?> father, Class<?> child) {

        if (father.isAssignableFrom(child)) {
            return true;
        }
        return false;
    }

    /**
     * 注入适配到的接口
     */
    protected Object setAdapterInterface(Object bean, String beanName) {

        if (bean instanceof Aware) {

            if (bean instanceof BeanFactoryAware)
                ((BeanFactoryAware) bean).setBeanFactory(this);

            if (bean instanceof BeanNameAware)
                ((BeanNameAware) bean).setBeanName(beanName);
        }

        return bean;
    }

    public void destory(){
        super.destroy();
    }
}
